﻿using SYMetro.DataObjects;
using SYMetro.ServiceContract.Membership;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Security;

namespace SYMetro.Web.MVC.App_Code
{
    public class MetrolMemberProvider : MembershipProvider
    {
        private MembershipConfigDataObject _config = null;
        private string name = null;
        private string description = null;

        internal static bool GetBooleanValue(NameValueCollection config, string valueName, bool defaultValue)
        {
            string sValue = config[valueName];
            if (sValue == null)
            {
                return defaultValue;
            }

            bool result;
            if (bool.TryParse(sValue, out result))
            {
                return result;
            }
            else
            {
                throw new ArgumentException(string.Format("{0}必需是布尔值", valueName));
            }
        }

        internal static int GetIntValue(NameValueCollection config, string valueName, int defaultValue, bool zeroAllowed, int maxValueAllowed)
        {
            string sValue = config[valueName];

            if (sValue == null)
            {
                return defaultValue;
            }

            int iValue;
            if (!Int32.TryParse(sValue, out iValue))
            {
                if (zeroAllowed)
                {
                    throw new ArgumentException(string.Format("{0}必需是正整数", valueName));                    
                }
                throw new ArgumentException(string.Format("{0}必需是整型", valueName));                        
            }

            if (zeroAllowed && iValue < 0)
            {
                throw new ArgumentException(string.Format("{0}必需是正整型", valueName));                        
            }

            if (!zeroAllowed && iValue <= 0)
            {
                throw new ArgumentException(string.Format("{0}必需是正整型", valueName));                        
            }

            if (maxValueAllowed > 0 && iValue > maxValueAllowed)
            {
                throw new ArgumentException(string.Format("{0}必需小于{1}", valueName, maxValueAllowed));
            }

            return iValue;
        }

        private MembershipUser MapToMembershipUser(UserDataObject u)
        {
            MembershipUser m = null;
            if (u != null)
            {
                m = new MembershipUser(name, u.UserName, u.ID, u.Email, u.PasswordQuestion, u.Comment, u.IsApproved.Value, u.IsLockedOut.Value, u.CreateDate.Value, u.LastLoginDate.Value, u.LastActivityDate.Value, u.LastPasswordChangedDate.Value, u.LastLockoutDate.Value);
            }
            return m;
        }

        private UserDataObject MapToUserDataObject(MembershipUser u)
        {
            UserDataObject m = null;
            if (u != null)
            {
                m = new UserDataObject()
                {
                    UserName = u.UserName,
                    ID = u.ProviderUserKey.ToString(),
                    Email = u.Email,
                    PasswordQuestion = u.PasswordQuestion,
                    Comment = u.Comment,
                    IsApproved = u.IsApproved,
                    IsLockedOut = u.IsLockedOut,
                    CreateDate = u.CreationDate,
                    LastLoginDate = u.LastLoginDate,
                    LastActivityDate = u.LastActivityDate,
                    LastPasswordChangedDate = u.LastPasswordChangedDate,
                    LastLockoutDate = u.LastLockoutDate
                };
            }
            return m;
        }

        public override void Initialize(string name, NameValueCollection config)
        {
            _config = new MembershipConfigDataObject();
            
            if (config == null)
                throw new ArgumentNullException("config");
            if (String.IsNullOrEmpty(name))
                name = "MetrolMemberProvider";
            if (string.IsNullOrEmpty(config["description"]))
            {
                config.Remove("description");
                config.Add("description", "MetrolMemberProvider");
            }
            base.Initialize(name, config);

            _config.EnablePasswordRetrieval = GetBooleanValue(config, "enablePasswordRetrieval", false);
            _config.EnablePasswordReset = GetBooleanValue(config, "enablePasswordReset", true);
            _config.RequiresQuestionAndAnswer = GetBooleanValue(config, "requiresQuestionAndAnswer", true);
            _config.RequiresUniqueEmail = GetBooleanValue(config, "requiresUniqueEmail", true);
            _config.MaxInvalidPasswordAttempts = GetIntValue(config, "maxInvalidPasswordAttempts", 5, false, 0);
            _config.PasswordAttemptWindow = GetIntValue(config, "passwordAttemptWindow", 10, false, 0);
            _config.MinRequiredPasswordLength = GetIntValue(config, "minRequiredPasswordLength", 7, false, 128);
            _config.MinRequiredNonalphanumericCharacters = GetIntValue(config, "minRequiredNonalphanumericCharacters", 1, true, 128);

            _config.PasswordStrengthRegularExpression = config["passwordStrengthRegularExpression"];
            if (_config.PasswordStrengthRegularExpression != null)
            {
                _config.PasswordStrengthRegularExpression = _config.PasswordStrengthRegularExpression.Trim();
                if (_config.PasswordStrengthRegularExpression.Length != 0)
                {
                    Regex regex = new Regex(_config.PasswordStrengthRegularExpression);
                }
            }
            else
            {
                _config.PasswordStrengthRegularExpression = string.Empty;
            }
            if (_config.MinRequiredNonalphanumericCharacters > _config.MinRequiredPasswordLength)
                throw new HttpException("MinRequiredNonalphanumericCharacters can not be more than MinRequiredPasswordLength");

            string strTemp = config["passwordFormat"];
            if (strTemp == null)
                strTemp = "Hashed";
            _config.PasswordFormat=strTemp;

            if (PasswordFormat == MembershipPasswordFormat.Hashed && EnablePasswordRetrieval)
                throw new HttpException("Provider can_not retrieve hashed password");
        }

        public override string ApplicationName
        {
            get;
            set;
        }

        public override bool ChangePassword(string username, string oldPassword, string newPassword)
        {
            using (var proxy = new WebServiceProxy<IUserService>())
            {
                return proxy.Channel.ChangePassword(_config, username, oldPassword, newPassword);
            }
        }

        public override bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion, string newPasswordAnswer)
        {
            using (var proxy = new WebServiceProxy<IUserService>())
            {
                return proxy.Channel.ChangePasswordQuestionAndAnswer(username, password, newPasswordQuestion, newPasswordAnswer);
            }
        }

        public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status)
        {
            MembershipUser user = null;
            status = MembershipCreateStatus.ProviderError;
            UserDataObject u = new UserDataObject() { 
                UserName=username,
                Password=password,
                Email=email,
                PasswordQuestion = passwordQuestion,
                PasswordAnswer=passwordAnswer,
                IsApproved=isApproved,
                ID=providerUserKey.ToString()
            };
            using (var proxy = new WebServiceProxy<IUserService>())
            {
                var lst = new UserDataObjectList();
                lst.Add(u);
                lst = proxy.Channel.CreateUser(_config, lst);
                if (lst.Count > 0)
                {
                    user = MapToMembershipUser(lst[0]);
                    status = MembershipCreateStatus.Success;
                }
            }
            return user;
        }

        public override bool DeleteUser(string username, bool deleteAllRelatedData)
        {
            using (var proxy = new WebServiceProxy<IUserService>())
            {
                return proxy.Channel.DeleteUser(username);
            }
        }

        //暂时未考虑分页
        public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords)
        {
            using (var proxy = new WebServiceProxy<IUserService>())
            {
                var lst = proxy.Channel.FindUsersByEmail(emailToMatch);
                totalRecords = lst.Count;
                MembershipUserCollection col = new MembershipUserCollection();
                lst.ForEach(u => col.Add(MapToMembershipUser(u)));
                return col;
            }
        }

        //暂时未考虑分页
        public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)
        {
            using (var proxy = new WebServiceProxy<IUserService>())
            {
                var lst = proxy.Channel.FindUsersByName(usernameToMatch);
                totalRecords = lst.Count;
                MembershipUserCollection col = new MembershipUserCollection();
                lst.ForEach(u => col.Add(MapToMembershipUser(u)));
                return col;
            }
        }

        //暂时未考虑分页
        public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)
        {
            using (var proxy = new WebServiceProxy<IUserService>())
            {
                var lst = proxy.Channel.GetAllUsers();
                totalRecords = lst.Count;
                MembershipUserCollection col = new MembershipUserCollection();
                lst.ForEach(u => col.Add(MapToMembershipUser(u)));
                return col;
            }
        }

        public override int GetNumberOfUsersOnline()
        {
            using (var proxy = new WebServiceProxy<IUserService>())
            {
                return proxy.Channel.GetNumberOfUsersOnline(_config);
            }
        }

        public override string GetPassword(string username, string answer)
        {
            using (var proxy = new WebServiceProxy<IUserService>())
            {
                return proxy.Channel.GetPassword(username, answer);
            }
        }

        public override MembershipUser GetUser(string username, bool userIsOnline)
        {
            using (var proxy = new WebServiceProxy<IUserService>())
            {
                return MapToMembershipUser(proxy.Channel.GetUser(username, userIsOnline));
            }
        }

        public override MembershipUser GetUser(object providerUserKey, bool userIsOnline)
        {
            using (var proxy = new WebServiceProxy<IUserService>())
            {
                return MapToMembershipUser(proxy.Channel.GetUser(Guid.Parse(providerUserKey.ToString()),userIsOnline));
            }
        }

        public override string GetUserNameByEmail(string email)
        {
            using (var proxy = new WebServiceProxy<IUserService>())
            {
                var u = proxy.Channel.GetUserNameByEmail(email);
                if (u != null)
                {
                    return u.Email;
                }
                else
                {
                    return string.Empty;
                }
            }
        }

        public override string ResetPassword(string username, string answer)
        {
            using (var proxy = new WebServiceProxy<IUserService>())
            {
                return proxy.Channel.ResetPassword(_config, username, answer);               
            }
        }

        public override bool UnlockUser(string userName)
        {
            using (var proxy = new WebServiceProxy<IUserService>())
            {
                return proxy.Channel.UnlockUser(userName);
            }
        }

        public override bool ValidateUser(string username, string password)
        {
            using (var proxy = new WebServiceProxy<IUserService>())
            {
                return proxy.Channel.ValidateUser(username, password);
            }
        }

        public override void UpdateUser(MembershipUser user)
        {
            using (var proxy = new WebServiceProxy<IUserService>())
            {
                UserDataObjectList list = new UserDataObjectList();
                list.Add(MapToUserDataObject(user));
                proxy.Channel.UpdateUser(_config,list);
            }
        }


        public override bool EnablePasswordReset
        {
            get { return _config.EnablePasswordReset; }
        }

        public override bool EnablePasswordRetrieval
        {
            get { return _config.EnablePasswordRetrieval; }
        }

        public override int MaxInvalidPasswordAttempts
        {
            get { return _config.MaxInvalidPasswordAttempts; }
        }

        public override int MinRequiredNonAlphanumericCharacters
        {
            get { return _config.MinRequiredNonalphanumericCharacters; }
        }

        public override int MinRequiredPasswordLength
        {
            get { return _config.MinRequiredPasswordLength; }
        }

        public override int PasswordAttemptWindow
        {
            get { return _config.PasswordAttemptWindow; }
        }

        public override MembershipPasswordFormat PasswordFormat
        {
            get
            {
                return (MembershipPasswordFormat)Enum.Parse(typeof(MembershipPasswordFormat), _config.PasswordFormat);
            }
        }

        public override string PasswordStrengthRegularExpression
        {
            get { return _config.PasswordStrengthRegularExpression; }
        }

        public override bool RequiresQuestionAndAnswer
        {
            get { return _config.RequiresQuestionAndAnswer; }
        }

        public override bool RequiresUniqueEmail
        {
            get { return _config.RequiresUniqueEmail; }
        }
    }
}